﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Common.Utilities.DLR;

namespace Workflows.Components.Reports
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    [OrmClass("ExcelReports", "Name", false)]
    public class ExcelReportInstruction:InstructionBase 
    {
        #region members
        private string _ReportName;
        /// <summary></summary>
        [OrmField("Name", SqlDbType.VarChar, 100, OrmFieldSerializationMethod.DefaultSerialization)]
        public string ReportName
        {
            get { return _ReportName; }
            set { _ReportName = value; }
        }

        private string _ConnectionString;
        /// <summary></summary>
        [OrmField("ConnectionString", SqlDbType.VarChar, 100, OrmFieldSerializationMethod.DefaultSerialization)]
        public string ConnectionString
        {
            get { return _ConnectionString; }
            set { _ConnectionString = value; }
        }

        private Dictionary<string,string> _ParameterNameValues;
        /// <summary></summary>
        [OrmField("_ParameterNameValues", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public Dictionary<string, string> ParameterNameValues
        {
            get { return _ParameterNameValues; }
            set { _ParameterNameValues = value; }
        }

        private List<string> _WorksheetNames;
        /// <summary></summary>
        [OrmField("WorksheetNames", SqlDbType.VarChar, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public List<string> WorksheetNames
        {
            get { return _WorksheetNames; }
            set { _WorksheetNames = value; }
        }

        private List<ExcelDataRegion> _DataRegions;
        /// <summary></summary>
        [OrmField("DataRegions", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public List<ExcelDataRegion> DataRegions
        {
            get { return _DataRegions; }
            set { _DataRegions = value; }
        }

        private string _Template;
        /// <summary></summary>
        [OrmField("Template", SqlDbType.Text, 1000, OrmFieldSerializationMethod.BinarySerialization)]
        public string Template
        {
            get { return _Template; }
            set { _Template = value; }
        }

        private string _ReportFilePath;
        /// <summary></summary>
        public string ReportFilePath
        {
            get
            {
                return this._ReportFilePath;
            }
            set
            {
                this._ReportFilePath = value;
            }
        }
        #endregion
        
        /// <summary>
        /// 
        /// </summary>
        public ExcelReportInstruction():base(Guid.Empty,Guid.Empty)
        {
            this._ReportName = string.Empty;
        }

        /// <summary></summary>
        public ExcelReportInstruction(Guid componentID, Guid jobTicketID, string reportName) 
            : base(componentID, jobTicketID)
        {
            if (!string.IsNullOrEmpty(reportName))
            {
                ORMapping<ExcelReportInstruction> orm = new ORMapping<ExcelReportInstruction>();
                ExcelReportInstruction instructionCopy =
                    orm.GetObjByKey(ConfigurationManager.ConnectionStrings["Workflow"].ConnectionString, reportName);
                this.ReportName = instructionCopy.ReportName;
                this.ReportFilePath = instructionCopy.ReportFilePath;
                this.ConnectionString = instructionCopy.ConnectionString;
                this.ParameterNameValues = instructionCopy.ParameterNameValues;
                this.WorksheetNames = instructionCopy.WorksheetNames;
                this.DataRegions = instructionCopy.DataRegions;
                this.Template = instructionCopy.Template;
            }
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode,"ReportName",this.ReportName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ReportFilePath",this.ReportFilePath);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ConnStr", this.ConnectionString);
            if(this.ParameterNameValues !=null && this.ParameterNameValues.Count>0)
            {
                XmlNode paramRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Parameters");
                foreach(string paramName in this.ParameterNameValues.Keys)
                {
                    XmlNode paramNode = XmlDataUtil.AddElement(ref xDoc, paramRootNode, "Parameter");
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "ParameterName",paramName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, paramNode, "ParameterValue",this.ParameterNameValues[paramName]);
                }
            }
            if(this.WorksheetNames !=null && this.WorksheetNames.Count>0)
            {
                XmlNode worksheetRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "Worksheets");
                foreach(string wksheetName in this.WorksheetNames)
                {
                    XmlNode worksheetNode = XmlDataUtil.AddElement(ref xDoc, worksheetRootNode, "Worksheet");
                    XmlDataUtil.UpdateAttribute(ref xDoc, worksheetNode, "Name",wksheetName);
                }
            }
            if(this.DataRegions !=null && this.DataRegions.Count>0)
            {
                XmlNode dataReagionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "DataRegions");
                foreach(ExcelDataRegion region in this.DataRegions)
                {
                    XmlNode regionNode = XmlDataUtil.AddElement(ref xDoc, dataReagionRootNode, "DataRegion");
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "WorksheetName", region.WorksheetName);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode,"Range",region.Range);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "Sql",region.Sql);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "FillAction",((int)region.FillAction).ToString());
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode,"KeyPosition",region.KeyPosition);
                    XmlDataUtil.UpdateAttribute(ref xDoc, regionNode, "KeyName",region.KeyName);
                    if(region.ExcelColumnBindings !=null && region.ExcelColumnBindings.Count>0)
                    {
                        foreach(string dataFieldName in region.ExcelColumnBindings.Keys)
                        {
                            XmlNode bindingNode = XmlDataUtil.AddElement(ref xDoc, regionNode, "Binding");
                            XmlDataUtil.UpdateAttribute(ref xDoc, bindingNode, "DataFieldName",dataFieldName);
                            XmlDataUtil.UpdateAttribute(ref xDoc, bindingNode, "ExcelColName",region.ExcelColumnBindings[dataFieldName]);
                        }
                    }
                }
            }
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Template",
                                        Base64Util.EncodeAsBase64(Encoding.Default.GetBytes(this.Template)));

            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                ExcelReportInstruction instruction = new ExcelReportInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.ReportName = XmlDataUtil.GetAttributeValue(xNode, "ReportName", "");
                instruction.ReportFilePath = XmlDataUtil.GetAttributeValue(xNode, "ReportFilePath", "");
                instruction.ConnectionString = XmlDataUtil.GetAttributeValue(xNode, "ConnStr", "");
                XmlNodeList paramNodes = xNode.SelectNodes("Parameters/Parameter");
                if(paramNodes !=null && paramNodes.Count>0)
                {
                    instruction.ParameterNameValues=new Dictionary<string, string>();
                    foreach(XmlNode paramNode in paramNodes)
                    {
                        string paramName = XmlDataUtil.GetAttributeValue(paramNode, "ParameterName", "");
                        string paramValue = XmlDataUtil.GetAttributeValue(paramNode, "ParameterValue", "");
                        instruction.ParameterNameValues.Add(paramName, paramValue);
                    }
                }
                XmlNodeList wksheetNodes = xNode.SelectNodes("Worksheets/Worksheet");
                if(wksheetNodes !=null && wksheetNodes.Count>0)
                {
                    instruction.WorksheetNames=new List<string>();
                    foreach(XmlNode wksheetNode in wksheetNodes)
                    {
                        instruction.WorksheetNames.Add(XmlDataUtil.GetAttributeValue(wksheetNode, "Name", ""));
                    }
                }
                XmlNodeList regionNodes = xNode.SelectNodes("DataRegions/DataRegion");
                if(regionNodes !=null && regionNodes.Count>0)
                {
                    instruction.DataRegions=new List<ExcelDataRegion>();
                    foreach(XmlNode regionNode in regionNodes)
                    {
                        ExcelDataRegion region = new ExcelDataRegion();
                        region.WorksheetName = XmlDataUtil.GetAttributeValue(regionNode, "WorksheetName", "");
                        region.Range = XmlDataUtil.GetAttributeValue(regionNode, "Range", "");
                        region.Sql = XmlDataUtil.GetAttributeValue(regionNode, "Sql", "");
                        region.FillAction =
                            (ExcelDataFillAction) int.Parse(
                                                      XmlDataUtil.GetAttributeValue(
                                                          regionNode, "FillAction",
                                                          ((int) ExcelDataFillAction.FillValue).ToString()));
                        region.KeyPosition = XmlDataUtil.GetAttributeValue(regionNode, "KeyPosition", "");
                        region.KeyName = XmlDataUtil.GetAttributeValue(regionNode, "KeyName", "");
                        region.ExcelColumnBindings=new Dictionary<string, string>();
                        XmlNodeList bindingNodes = regionNode.SelectNodes("Binding");
                        if (bindingNodes != null && bindingNodes.Count > 0)
                        {
                            foreach(XmlNode bindingNode in bindingNodes)
                            {
                                string dataFieldName = XmlDataUtil.GetAttributeValue(bindingNode, "DataFieldName", "");
                                string excelColName = XmlDataUtil.GetAttributeValue(bindingNode, "ExcelColName", "");
                                region.ExcelColumnBindings.Add(dataFieldName,excelColName);
                            }
                        }
                        instruction.DataRegions.Add(region);
                    }
                }
                instruction.Template =
                    Encoding.Default.GetString(
                        Base64Util.DecodeAsBytes(XmlDataUtil.GetAttributeValue(xNode, "Template", "")));

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }

        //public override Dictionary<string, Type> GetBindableMemberNames(Type[] excludeMemberFromTypes)
        //{
        //    Dictionary<string, Type> bindableMembers = base.GetBindableMemberNames(excludeMemberFromTypes);
        //    if(this.ParameterNameValues !=null && this.ParameterNameValues.Count>0)
        //    {
        //        foreach(string paramName in this.ParameterNameValues.Keys)
        //        {
        //            if(bindableMembers.ContainsKey(paramName))
        //            {
        //                bindableMembers[paramName] = typeof (string);
        //            }
        //            else
        //            {
        //                bindableMembers.Add(paramName,typeof(string));
        //            }
        //        }
        //    }
        //    return bindableMembers;
        //}

        //public override object ReadMemberValue(string memberName)
        //{
        //    if (this.ParameterNameValues != null && this.ParameterNameValues.Count > 0 && this.ParameterNameValues.ContainsKey(memberName))
        //    {
        //        return this.ParameterNameValues[memberName];
        //    }
        //    else
        //    {
        //        return base.ReadMemberValue(memberName);
        //    }
        //}

        //public override void SetMemberValue(string memberName, object memberValue)
        //{
        //    if (this.ParameterNameValues != null && this.ParameterNameValues.ContainsKey(memberName))
        //    {
        //        this.ParameterNameValues[memberName] = memberValue == null
        //                                                   ? string.Empty
        //                                                   :
        //                                                       memberValue.ToString();
        //    }
        //    else
        //    {
        //        base.SetMemberValue(memberName, memberValue);
        //    }
        //}

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <returns></returns>
        //public object Clone()
        //{
        //    ExcelReportInstruction instructionCopy = new ExcelReportInstruction();
        //    instructionCopy.ReportName = this.ReportName;
        //    instructionCopy.ReportFilePath = this.ReportFilePath;
        //    instructionCopy.ConnectionString = this.ConnectionString;
        //    instructionCopy.ParameterNameValues = this.ParameterNameValues;
        //    instructionCopy.WorksheetNames = this.WorksheetNames;
        //    instructionCopy.DataRegions = this.DataRegions;
        //    instructionCopy.Template = this.Template;
        //    return instructionCopy;
        //}
    }
}
